"""
Redis连接池管理器
统一管理Redis连接池，减少连接开销，提升性能

作者: 架构重构优化
日期: 2025-01-05
"""

import logging
import threading
import time
from typing import Dict, Optional, Any
import redis
from redis.connection import ConnectionPool
from .config_manager import ConfigManager

logger = logging.getLogger(__name__)

class RedisPoolManager:
    """
    Redis连接池管理器
    提供统一的Redis连接池管理，支持连接复用和健康检查
    """
    
    def __init__(self, config: ConfigManager):
        """
        初始化Redis连接池管理器
        
        Args:
            config: 配置管理器实例
        """
        self.config = config
        self._pools: Dict[str, ConnectionPool] = {}
        self._clients: Dict[str, redis.Redis] = {}
        self._lock = threading.Lock()
        # 简化版本：移除复杂的统计和健康检查
        
        logger.info("Redis连接池管理器初始化完成")

    def get_client(self, pool_name: str = "default") -> Optional[redis.Redis]:
        """
        获取Redis客户端实例
        
        Args:
            pool_name: 连接池名称
            
        Returns:
            Redis客户端实例，如果失败则返回None
        """
        try:
            with self._lock:
                # 检查是否已存在客户端
                if pool_name in self._clients:
                    client = self._clients[pool_name]
                    # 简单的连接检查
                    try:
                        client.ping()
                        return client
                    except:
                        # 连接无效，移除并重新创建
                        logger.warning(f"Redis客户端 {pool_name} 连接无效，重新创建")
                        del self._clients[pool_name]

                # 创建新的客户端
                client = self._create_client(pool_name)
                if client:
                    self._clients[pool_name] = client
                    logger.info(f"Redis客户端 {pool_name} 创建成功")
                    return client
                else:
                    return None
                    
        except Exception as e:
            logger.error(f"获取Redis客户端失败: {e}")
            return None

    def _create_client(self, pool_name: str) -> Optional[redis.Redis]:
        """创建Redis客户端"""
        try:
            # 创建连接池
            pool = self._create_pool(pool_name)
            if not pool:
                return None
            
            # 创建客户端
            client = redis.Redis(
                connection_pool=pool,
                decode_responses=True,
                socket_keepalive=True,
                socket_keepalive_options={},
                health_check_interval=30
            )
            
            # 测试连接
            client.ping()
            
            return client
            
        except Exception as e:
            logger.error(f"创建Redis客户端失败: {e}")
            return None

    def _create_pool(self, pool_name: str) -> Optional[ConnectionPool]:
        """创建连接池"""
        try:
            if pool_name in self._pools:
                return self._pools[pool_name]
            
            # 创建新的连接池
            pool = ConnectionPool.from_url(
                self.config.redis.url,
                max_connections=self.config.redis.max_connections,
                socket_timeout=self.config.redis.socket_timeout,
                socket_connect_timeout=self.config.redis.socket_connect_timeout,
                retry_on_timeout=self.config.redis.retry_on_timeout,
                decode_responses=True,
                # 连接池优化参数
                socket_keepalive=True,
                socket_keepalive_options={},
                health_check_interval=30
            )
            
            self._pools[pool_name] = pool
            logger.info(f"Redis连接池 {pool_name} 创建成功")

            return pool

        except Exception as e:
            logger.error(f"创建Redis连接池失败: {e}")
            return None


    def execute_command(self, command: str, *args, pool_name: str = "default", **kwargs) -> Any:
        """
        执行Redis命令
        
        Args:
            command: Redis命令
            *args: 命令参数
            pool_name: 连接池名称
            **kwargs: 命令关键字参数
            
        Returns:
            命令执行结果
        """
        client = self.get_client(pool_name)
        if not client:
            raise ConnectionError(f"无法获取Redis客户端: {pool_name}")
        
        try:
            # 获取命令方法
            cmd_method = getattr(client, command.lower())
            return cmd_method(*args, **kwargs)

        except Exception as e:
            logger.error(f"执行Redis命令失败 {command}: {e}")
            # 如果是连接错误，移除客户端以便重新创建
            if "connection" in str(e).lower() and pool_name in self._clients:
                del self._clients[pool_name]
            raise

    def close_all(self):
        """关闭所有连接池和客户端"""
        try:
            with self._lock:
                # 关闭所有客户端
                for client in self._clients.values():
                    try:
                        client.close()
                    except:
                        pass
                self._clients.clear()

                # 关闭所有连接池
                for pool in self._pools.values():
                    try:
                        pool.disconnect()
                    except:
                        pass
                self._pools.clear()

            logger.info("所有Redis连接池已关闭")

        except Exception as e:
            logger.error(f"关闭Redis连接池失败: {e}")

# 全局Redis连接池管理器实例
_redis_pool_manager_instance = None
_redis_pool_manager_lock = threading.Lock()

def get_redis_pool_manager(config: ConfigManager = None) -> RedisPoolManager:
    """获取全局Redis连接池管理器实例（单例模式）"""
    global _redis_pool_manager_instance
    if _redis_pool_manager_instance is None:
        with _redis_pool_manager_lock:
            if _redis_pool_manager_instance is None:
                if config is None:
                    from .config_manager import get_config
                    config = get_config()
                _redis_pool_manager_instance = RedisPoolManager(config)
    return _redis_pool_manager_instance

def reset_redis_pool_manager():
    """重置全局Redis连接池管理器实例（用于测试）"""
    global _redis_pool_manager_instance
    with _redis_pool_manager_lock:
        if _redis_pool_manager_instance:
            _redis_pool_manager_instance.close_all()
        _redis_pool_manager_instance = None
